package com.openlogic.j.client;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.openlogic.j.Json;
import com.openlogic.j.RequestExecutor;
import com.openlogic.j.SyncOrAsyncOrStreaming;
import com.openlogic.j.api.OpenDecisionApi;
import com.openlogic.j.completion.CompletionRequest;
import com.openlogic.j.completion.CompletionResponse;
import com.openlogic.j.http.AuthorizationHeaderInjector;
import com.openlogic.j.http.GenericHeaderInjector;
import com.openlogic.j.http.RequestLoggingInterceptor;
import com.openlogic.j.http.ResponseLoggingInterceptor;

import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;

/**
 * @ClassName: DefaultOpenDecisionClient
 * @Description: 默认实现-决策调用实现
 * @author weiyongpeng
 * @date 2025年2月21日 上午9:46:59
 */
public class DefaultOpenDecisionClient extends OpenDecisionClient {

	private static final Logger log = LoggerFactory.getLogger(DefaultOpenDecisionClient.class);

	private final String baseUrl;

	private final String apiVersion;

	private final OpenDecisionApi openDecisionApi;

	private final OkHttpClient okHttpClient;

	@Override
	public SyncOrAsyncOrStreaming<CompletionResponse> decisionFlow(OpenDecisionClientContext context,
			CompletionRequest request) {
		CompletionRequest syncRequest = CompletionRequest.builder().from(request).build();

		return new RequestExecutor<>(
				openDecisionApi.decisionFlow(context.headers(), syncRequest.getData(), syncRequest.getId(),
						syncRequest.getOperator(), apiVersion),
				r -> r, okHttpClient, formatUrl("flow"), () -> CompletionRequest.builder().from(request).build(),
				CompletionResponse.class, r -> r, false);
	}

	@Override
	public SyncOrAsyncOrStreaming<CompletionResponse> decisionTree(OpenDecisionClientContext context,
			CompletionRequest request) {
		CompletionRequest syncRequest = CompletionRequest.builder().from(request).build();

		return new RequestExecutor<>(openDecisionApi.decisionTree(context.headers(), syncRequest.getData(), syncRequest.getId(),
				syncRequest.getOperator(), apiVersion), r -> r,
				okHttpClient, formatUrl("tree"), () -> CompletionRequest.builder().from(request).build(),
				CompletionResponse.class, r -> r, false);
	}

	@Override
	public SyncOrAsyncOrStreaming<CompletionResponse> decisionTable(OpenDecisionClientContext context,
			CompletionRequest request) {
		CompletionRequest syncRequest = CompletionRequest.builder().from(request).build();

		return new RequestExecutor<>(openDecisionApi.decisionTable(context.headers(), syncRequest.getData(), syncRequest.getId(),
				syncRequest.getOperator(), apiVersion), r -> r,
				okHttpClient, formatUrl("table"), () -> CompletionRequest.builder().from(request).build(),
				CompletionResponse.class, r -> r, false);
	}

	@Override
	public SyncOrAsyncOrStreaming<CompletionResponse> decisionCrossTable(OpenDecisionClientContext context,
			CompletionRequest request) {
		CompletionRequest syncRequest = CompletionRequest.builder().from(request).build();

		return new RequestExecutor<>(openDecisionApi.decisionCrossTable(context.headers(), syncRequest.getData(), syncRequest.getId(),
				syncRequest.getOperator(), apiVersion),
				r -> r, okHttpClient, formatUrl("crosstable"), () -> CompletionRequest.builder().from(request).build(),
				CompletionResponse.class, r -> r, false);
	}

	@Override
	public SyncOrAsyncOrStreaming<CompletionResponse> decisionScoreCard(OpenDecisionClientContext context,
			CompletionRequest request) {
		CompletionRequest syncRequest = CompletionRequest.builder().from(request).build();

		return new RequestExecutor<>(openDecisionApi.decisionScoreCard(context.headers(), syncRequest.getData(), syncRequest.getId(),
				syncRequest.getOperator(), apiVersion),
				r -> r, okHttpClient, formatUrl("scorecard"), () -> CompletionRequest.builder().from(request).build(),
				CompletionResponse.class, r -> r, false);
	}

	/**
	 * 描述：生成请求地址url
	 * 
	 * @Title: formatUrl
	 * @param endPoint
	 * @return
	 * @author weiyongpeng
	 * @date 2025年2月24日 上午9:29:22
	 */
	private String formatUrl(String endPoint) {
		// http://localhost/rule/client/v1/ + flow + /?api-version=v1
		return baseUrl + endPoint + apiVersionQueryParam();
	}

	/**
	 * 描述：接口版本参数
	 * 
	 * @Title: apiVersionQueryParam
	 * @return
	 * @author weiyongpeng
	 * @date 2025年2月24日 上午9:29:10
	 */
	private String apiVersionQueryParam() {
		if (apiVersion == null || apiVersion.trim().isEmpty()) {
			return "";
		}
		return "?api-version=" + apiVersion;
	}

	public DefaultOpenDecisionClient(String apikey) {
		this(new Builder().apiKey(apikey));
	}

	private DefaultOpenDecisionClient(Builder serviceBuilder) {
		this.apiVersion = serviceBuilder.apiVersion;
		this.baseUrl = serviceBuilder.baseUrl;

		OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder().callTimeout(serviceBuilder.callTimeout)
				.connectTimeout(serviceBuilder.connectTimeout).readTimeout(serviceBuilder.readTimeout)
				.writeTimeout(serviceBuilder.writeTimeout);

		if ((serviceBuilder.apiKey == null || StringUtils.isBlank(serviceBuilder.apiKey))
				&& !serviceBuilder.isAnonymous) {
			throw new IllegalArgumentException("apiKey must be defined");
		}
		// token设置
		if (serviceBuilder.apiKey != null && !serviceBuilder.isAnonymous) {
			okHttpClientBuilder.addInterceptor(new AuthorizationHeaderInjector(serviceBuilder.apiKey));
		}
		// 自定义请求头
		Map<String, String> headers = new HashMap<>();
		if (serviceBuilder.customHeaders != null) {
			headers.putAll(serviceBuilder.customHeaders);
		}
		if (!headers.isEmpty()) {
			okHttpClientBuilder.addInterceptor(new GenericHeaderInjector(headers));
		}

		if (serviceBuilder.logRequests) {
			okHttpClientBuilder.addInterceptor(new RequestLoggingInterceptor(serviceBuilder.logLevel));
		}

		if (serviceBuilder.logResponses) {
			okHttpClientBuilder.addInterceptor(new ResponseLoggingInterceptor(serviceBuilder.logLevel));
		}

		this.okHttpClient = okHttpClientBuilder.build();

		Retrofit.Builder retrofitBuilder = new Retrofit.Builder().baseUrl(serviceBuilder.baseUrl).client(okHttpClient);

		retrofitBuilder.addConverterFactory(JacksonConverterFactory.create(Json.OBJECT_MAPPER));

		this.openDecisionApi = retrofitBuilder.build().create(OpenDecisionApi.class);
	}

	public static Logger getLog() {
		return log;
	}

	public OpenDecisionApi getOpenDecisionApi() {
		return openDecisionApi;
	}

	@Override
	public int hashCode() {
		return Objects.hash(apiVersion, baseUrl, okHttpClient, openDecisionApi);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		DefaultOpenDecisionClient other = (DefaultOpenDecisionClient) obj;
		return Objects.equals(apiVersion, other.apiVersion) && Objects.equals(baseUrl, other.baseUrl)
				&& Objects.equals(okHttpClient, other.okHttpClient)
				&& Objects.equals(openDecisionApi, other.openDecisionApi);
	}

	@Override
	public String toString() {
		return "DefaultOpenDecisionClient [baseUrl=" + baseUrl + ", apiVersion=" + apiVersion + ", openDecisionApi="
				+ openDecisionApi + ", okHttpClient=" + okHttpClient + "]";
	}

	public String getBaseUrl() {
		return baseUrl;
	}

	public String getApiVersion() {
		return apiVersion;
	}

	public OkHttpClient getOkHttpClient() {
		return okHttpClient;
	}

	public static Builder builder() {
		return new Builder();
	}

	public static class Builder extends OpenDecisionClient.Builder<DefaultOpenDecisionClient, Builder> {

		public DefaultOpenDecisionClient build() {
			return new DefaultOpenDecisionClient(this);
		}
	}

}
